#include "DoubleLinkList.h"

node* CreateNode(ElementType element)
{
    node* newNode = (node*)malloc(sizeof(node));
    if (newNode == NULL)
    {
        printf("CreateNode malloc error!\n");
        return NULL;
    }
    newNode->next = NULL;
    newNode->prev = NULL;
    newNode->value = element;
    return newNode;
}

void InitDLlist(DLlist *list)
{
    list->head = CreateNode(0);
    if (list->head == NULL)
    {
        printf("head node create error!\n");
        return;
    }
    list->tail = list->head;
    list->len = 0;
}

void InsertDLlistTail(DLlist *list, ElementType element)
{
    node *newNode = CreateNode(element);
    if (newNode == NULL)
    {
        printf("InsertDLlistTail malloc error!\n");
        return;
    }
    list->tail->next = newNode;
    newNode->prev = list->tail;
    list->tail = newNode;
    list->len++;
}

void InsertDLlistHead(DLlist *list, ElementType element)
{
    node *newNode = CreateNode(element);
    if (newNode == NULL)
    {
        printf("InsertDLlistHead malloc error!\n");
        return;
    }
    newNode->next = list->head->next;
    newNode->prev = list->head;
    if (list->head->next != NULL)
    {
        list->head->next->prev = newNode;
    }
    else
    {
        list->tail = newNode;
    }
    list->head->next = newNode;
    list->len++;
}

void InsertByIndex(DLlist *list, int index, ElementType element)
{
    if (index < 0 || index >= list->len)
    {
        printf("illegel !\n");
        return;
    }
    node *newNode = CreateNode(element);
    if (newNode == NULL)
    {
        return;
    }

    node *travelPoint = list->head->next;
    for (int i = 0; i < index; i++) 
    {
        travelPoint = travelPoint->next;
    }
    newNode->next = travelPoint;
    newNode->prev = travelPoint->prev;
    travelPoint->prev->next = newNode;
    travelPoint->prev = newNode;
    list->len++;
}

void Travel(DLlist *list, void (*funcPtr)(ElementType))
{
    printf("len: %d\n", list->len);
    node *travel = list->head->next;
    for (int i = 0; i < list->len; i++)
    {
        funcPtr(travel->value);
        travel = travel->next;
    }
    printf("\n");
}

void ReTravel(DLlist *list, void (*funcPtr)(ElementType))
{
    if (funcPtr == NULL)
    {
        return;
    }
    printf("len: %d\n", list->len);
    node *travel = list->tail;
    while (travel != list->head)
    {
        funcPtr(travel->value);
        travel = travel->prev;
    }
    printf("\n");
}

node* FindByIndex(DLlist *list, int index)
{
    if (index < 0 || index > list->len)
    {
        printf("illegel !\n");
        return NULL;
    }
    node *travel = list->head->next;
    for (int i = 0; i < index; i++)
    {
        travel = travel->next;
    }
    return travel;
}

void RemoveByIndex(DLlist *list, int index)
{
    node *nd = FindByIndex(list, index);
    if (nd == NULL)
    {
        return;
    }
    nd->prev->next = nd->next;
    if (nd->next != NULL)
    {
        nd->next->prev = nd->prev;
    }
    else
    {
        list->tail = nd->prev;
    }
    free(nd);
    list->len--;
}

void RemoveByElement(DLlist *list, ElementType element, bool (*funcPtr)(ElementType, ElementType))
{
    if (funcPtr == NULL)
    {
        return;
    }
    for (int i = 0; i < list->len; i++)
    {
        if (funcPtr(element, FindByIndex(list, i)->value) == true)
        {
            RemoveByIndex(list, i);
            i--;
        }
    }
}

void FreeDLlist(DLlist *list, void (*funcPtr)(ElementType))
{
   node *travelPoint = list->head->next;
   while (travelPoint != NULL)
   {
        if (funcPtr != NULL)
        {
            funcPtr(travelPoint->value);
        }
        node *next = travelPoint->next;
        free(travelPoint);
        travelPoint = next;
   }
   free(list->head);
   list->head = list->tail = NULL;
   list->len = 0;
}

DLlist FindByElement(DLlist *list, ElementType element, bool (*funcPtr)(ElementType, ElementType))
{
    DLlist result;
    InitDLlist(&result);
    if (funcPtr == NULL)
    {
        return result;
    }
    node *travel = list->head->next;
    while (travel != NULL)
    {
        if (funcPtr(element, travel->value) == true)
        {
            InsertDLlistTail(&result, travel->value);
        }
        travel = travel->next;
    }
    return result;
}
